/*
 *  Author: Rico Yang
 *  gcc version: (Ubuntu 9.3.0-10ubuntu2)
 */

// #include <unistd.h>
#include "seqListBasicOps.h"

short increaseSize(SeqList *list) {
    DataType *newData = realloc(list->data, sizeof(DataType)*(list->maxSize+INCREASE_SIZE));
    if (newData == NULL) {
        printf("Expanded list size failed.\n");
        return -1;
    }
    list->data = newData;
    list->maxSize += INCREASE_SIZE;
    printf("Expanded list size successfully.\n");
    return 0;
}

void initSeqList(SeqList *list) {
    list->data = malloc(sizeof(DataType) * INIT_SIZE);
    if (list->data == NULL) {
        printf("Initialize SeqList failed!\n");
        exit(1);
    }
    list->maxSize = INIT_SIZE;
    list->lenth = 0;
}

// case 1
void displaySeqList(SeqList *list) {
    if (list->lenth == 0) {
        printf("There is nothing cause of empty list.\n");
    } else {
        printf("The list data: ");
        // 输出到倒数第二个数据
        for (int i = 0; i < list->lenth-1; i++) {
            printf("%d, ", list->data[i]);
        }
        // 为数据显示美观, 最后一个元素单独放出来
        printf("%d.\n", list->data[list->lenth-1]);
    }
}

// case 2
void clearSeqList(SeqList *list) {
    list->lenth = 0;
    printf("Cleared list successfully.\n");
}

// case 3
void isEmpty(SeqList *list) {
    if (list->lenth == 0) {
        printf("Yes, the list is empty!\n");
    } else {
        printf("No, the list have data.\n");
    }
}

// case 4
void isFull(SeqList *list) {
    if (list->lenth == list->maxSize) {
        printf("Yes, it's full now.\n");
    } else {
        printf("No, it still can save data.\n");
    }
}

// case 5
short insertAtTheEnd(SeqList *list, DataType userData) {
    if (list->lenth == list->maxSize) {
        printf("Insert data failed cause of full list.\n");
        printf("Do you want to expand list size now?(y or n): ");
        char ch;
        scanf("%c", &ch);
        if (ch == 'y' || ch == 'Y') {
            increaseSize(list);
            printf("Now you can insert %d more data.\n\n", list->maxSize - list->lenth);
        } else {
            return -1;
        }
    }
    list->data[list->lenth] = userData;
    list->lenth++;
    // {   // 延迟 loading, 增加程序体验效果, 需要包含 unistd.h
    //     printf("Inserting.");
    //     fflush(stdout);
    //     sleep(1);
    //     printf(".");
    //     fflush(stdout);
    //     sleep(1);
    //     printf(".\n");
    // }
    return 0;
}

// case 6
short insertAtTheBeginning(SeqList *list, DataType userData) {
    if (list->lenth == list->maxSize) {
        printf("Insert data failed cause of full list.\n");
        printf("Do you want to expand list size now?(y or n): ");
        char ch;
        scanf("%c", &ch);
        if (ch == 'y' || ch == 'Y') {
            increaseSize(list);
            printf("Now you can insert %d more data.\n\n", list->maxSize - list->lenth);
        } else {
            return -1;
        }
    }
    for (int i = list->lenth; i > 0; i--) {
        list->data[i] = list->data[i-1];
    }
    list->data[0] = userData;
    list->lenth++;
    return 0;
}

// case 7
short insertByLocation(SeqList *list, int location, DataType userData) {
    if (list->lenth == list->maxSize) {
        printf("Insert data failed cause of full list.\n");
        printf("Do you want to expand list size now?(y or n): ");
        char ch;
        scanf("%c", &ch);
        if (ch == 'y' || ch == 'Y') {
            increaseSize(list);
            printf("Now you can insert %d more data.\n\n", list->maxSize - list->lenth);
        } else {
            return -1;
        }
    }
    if (location < 0 || location > list->lenth+1) {
        printf("Illegal location.\n");
        return -1;
    }
    for (int i = list->lenth; i >= location; i--) {
        list->data[i] = list->data[i-1];
    }
    list->data[location-1] = userData;
    list->lenth++;
    return 0;
}

// case 8
short insertByArray(SeqList *list) {
    if (list->lenth == list->maxSize) {
        printf("Insert data failed cause of full list.\n");
        printf("Do you want to expand list size now?(y or n): ");
        eatline;
        char ch;
        scanf("%c", &ch);
        if (ch == 'y' || ch == 'Y') {
            increaseSize(list);
        } else {
            return -1;
        }
    }
    printf("You can insert %d more data.\n\n", list->maxSize - list->lenth);
    DataType array[list->maxSize - list->lenth];
    int flag = 0;   // 记录输入数据的个数
    printf("Input the data array: ");
    eatline;
    for (int i = 0; i < list->maxSize-list->lenth; i++) {
        scanf("%d", &array[i]);
        flag++;
        char ch = getchar();
        if (ch == '\n') {
            break;
        }
    }
    for (int i = 0; i < flag; i++) {
        insertAtTheEnd(list, array[i]);
    }
    return 0;
}

// case 9
void getListLenth(SeqList *list) {
    printf("The lenth of the list is %d now.\n", list->lenth);
}

// case 10
short popAtTheEnd(SeqList *list) {
    if (list->lenth == 0) {
        return -1;
    }
    list->lenth--;
    return 0;
}

// case 11
short popAtTheBeginning(SeqList *list) {
    if (list->lenth == 0) {
        return -1;
    }
    for (int i = 0; i < list->lenth; i++) {
        list->data[i] = list->data[i+1];
    }
    list->lenth--;
    return 0;
}

// case 12
short popByLocation(SeqList *list, int location) {
    if (list->lenth == 0) {
        return -1;
    }
    if (location < 0 || location > list->lenth) {
        return -2;
    }
    for (int i = location; i < list->lenth; i++) {
        list->data[i-1] = list->data[i];
    }
    list->lenth--;
    return 0;
}

// case 13
short popByData(SeqList *list, DataType userData) {
    int location = getLocationByData(list, userData);
    if (location == -1) {
        printf("No result.\n");
    }
    short result = popByLocation(list, location);
    if (result == -1) {
        printf("There is nothing todo cause of empty list.\n");
    } else if (result == -2) {
        printf("Illegal location.\n");
    } else {
        printf("Successfully poped data.\n");
    }
    return 0;
}

// case 14
int getLocationByData(SeqList *list, DataType userData) {
    for (int i = 0; i < list->lenth; i++) {
        if (list->data[i] == userData) {
            return i+1;
        }
    }
    return -1;
}

// case 15
DataType getDataByLocation(SeqList *list, int location) {
    if (location < 0 || location > list->lenth) {
        return -1;
    }
    return list->data[location-1];
}

// case 16
void sortList(SeqList *list) {
    DataType tmp;
    for (int i = 0; i < list->lenth-1; i++) {
        for (int j = 0; j < list->lenth-1; j++) {
            if (list->data[j] > list->data[j+1]) {
                tmp = list->data[j];
                list->data[j] = list->data[j+1];
                list->data[j+1] = tmp;
            }
        }
    }
    printf("Successfully sorted.\n");
}

// case 17
void reverseList(SeqList *list) {
    DataType tmp;
    for (int i = 0, j = list->lenth-1; i < (list->lenth)/2; i++, j--) {
        tmp = list->data[i];
        list->data[i] = list->data[j];
        list->data[j] = tmp;
    }
    printf("Successfully sorted.\n");
}

// case 18
void destroyList(SeqList *list) {
    free(list->data);
    list->data = NULL;
    list->lenth = 0;
    list->maxSize = 0;
    printf("List destroyed successfully!\n");
}

// 将两个顺序表合并到一个新的顺序表中并从小到大排列
void mergeToNewLists(SeqList *dest, SeqList *srcLA, SeqList *srcLB) {
    dest->maxSize = srcLA->lenth + srcLB->lenth;
    dest->data = malloc(sizeof(DataType) * dest->maxSize);
    if (dest->data == NULL) {
        printf("Merge failed.\n");
    }

    int lAindex, lBindex, lMindex = lAindex = lBindex = 0;

    while (lAindex < srcLA->lenth || lBindex < srcLB->lenth) {
        if (lAindex >= srcLA->lenth) {
            dest->data[lMindex++] = srcLB->data[lBindex++];
            continue;
        } else if (lBindex >= srcLB->lenth) {
            dest->data[lMindex++] = srcLA->data[lAindex++];
            continue;
        }
        if (srcLA->data[lAindex] < srcLB->data[lBindex]) {
            dest->data[lMindex++] = srcLA->data[lAindex++];
        } else {
            dest->data[lMindex++] = srcLB->data[lBindex++];
        }
    }
    // 下面注释掉的语句作用跟上面 while 循环中包含 continue 的 if 语句相同
    // while (lAindex < srcLA->lenth) {
    //     dest->data[lMindex++] = srcLA->data[lAindex++];
    // }
    // while (lBindex < srcLB->lenth) {
    //     dest->data[lMindex++] = srcLB->data[lBindex++];
    // }
    dest->lenth = srcLA->lenth + srcLB->lenth;
}

void mergeWithoutDup(SeqList *srcLA, SeqList *srcLB) {
    for (int i = 0; i < srcLB->lenth; i++) {
        if (getLocationByData(srcLA, srcLB->data[i]) == -1) {
            insertAtTheEnd(srcLA, srcLB->data[i]);
        } else {
            continue;
        }
    }
}
